"""
存储管理器
负责处理文件的上传、下载、删除等操作
"""
import os
import tempfile
import logging
from typing import Optional
import boto3
from botocore.exceptions import ClientError, NoCredentialsError
from app.config import settings

logger = logging.getLogger(__name__)


class StorageManager:
    """存储管理器"""

    def __init__(self):
        self.endpoint_url = settings.S3_ENDPOINT
        self.access_key = settings.S3_ACCESS_KEY
        self.secret_key = settings.S3_SECRET_KEY
        self.bucket_name = settings.S3_BUCKET
        self.use_ssl = settings.S3_USE_SSL
        self.verify_ssl = settings.S3_VERIFY_SSL

        # 初始化S3客户端
        self._init_s3_client()

    def _init_s3_client(self):
        """初始化S3客户端"""
        try:
            self.s3_client = boto3.client(
                's3',
                endpoint_url=self.endpoint_url,
                aws_access_key_id=self.access_key,
                aws_secret_access_key=self.secret_key,
                region_name=settings.S3_REGION,
                use_ssl=self.use_ssl,
                verify=self.verify_ssl
            )

            # 检查bucket是否存在，不存在则创建
            self._ensure_bucket_exists()

            logger.info("S3 client initialized successfully")

        except Exception as e:
            logger.error(f"Failed to initialize S3 client: {e}")
            raise

    def _ensure_bucket_exists(self):
        """确保bucket存在"""
        try:
            self.s3_client.head_bucket(Bucket=self.bucket_name)
        except ClientError as e:
            if e.response['Error']['Code'] == '404':
                # Bucket不存在，尝试创建
                try:
                    self.s3_client.create_bucket(Bucket=self.bucket_name)
                    logger.info(f"Bucket '{self.bucket_name}' created successfully")
                except ClientError as create_error:
                    logger.error(f"Failed to create bucket: {create_error}")
                    raise
            else:
                logger.error(f"Failed to check bucket: {e}")
                raise

    async def upload_file(
        self,
        content: bytes,
        file_path: str,
        content_type: str = "application/octet-stream"
    ) -> str:
        """
        上传文件到S3

        Args:
            content: 文件内容
            file_path: 文件路径
            content_type: 内容类型

        Returns:
            文件URL
        """
        try:
            # 上传文件
            self.s3_client.put_object(
                Bucket=self.bucket_name,
                Key=file_path,
                Body=content,
                ContentType=content_type
            )

            # 生成文件URL
            file_url = f"{self.endpoint_url}/{self.bucket_name}/{file_path}"
            logger.info(f"File uploaded successfully: {file_path}")

            return file_url

        except Exception as e:
            logger.error(f"Failed to upload file {file_path}: {e}")
            raise

    async def download_file(self, file_url: str) -> str:
        """
        从S3下载文件

        Args:
            file_url: 文件URL

        Returns:
            本地文件路径
        """
        try:
            # 从URL解析文件路径
            if f"/{self.bucket_name}/" in file_url:
                file_path = file_url.split(f"/{self.bucket_name}/", 1)[1]
            else:
                file_path = file_url

            # 下载文件到临时目录
            temp_dir = tempfile.gettempdir()
            filename = os.path.basename(file_path)
            local_path = os.path.join(temp_dir, f"download_{filename}")

            response = self.s3_client.get_object(
                Bucket=self.bucket_name,
                Key=file_path
            )

            with open(local_path, 'wb') as f:
                f.write(response['Body'].read())

            logger.info(f"File downloaded successfully: {file_path} -> {local_path}")
            return local_path

        except Exception as e:
            logger.error(f"Failed to download file {file_url}: {e}")
            raise

    async def delete_file(self, file_url: str) -> bool:
        """
        删除S3中的文件

        Args:
            file_url: 文件URL

        Returns:
            是否删除成功
        """
        try:
            # 从URL解析文件路径
            if f"/{self.bucket_name}/" in file_url:
                file_path = file_url.split(f"/{self.bucket_name}/", 1)[1]
            else:
                file_path = file_url

            # 删除文件
            self.s3_client.delete_object(
                Bucket=self.bucket_name,
                Key=file_path
            )

            logger.info(f"File deleted successfully: {file_path}")
            return True

        except Exception as e:
            logger.error(f"Failed to delete file {file_url}: {e}")
            return False

    async def file_exists(self, file_url: str) -> bool:
        """
        检查文件是否存在

        Args:
            file_url: 文件URL

        Returns:
            文件是否存在
        """
        try:
            # 从URL解析文件路径
            if f"/{self.bucket_name}/" in file_url:
                file_path = file_url.split(f"/{self.bucket_name}/", 1)[1]
            else:
                file_path = file_url

            # 检查文件是否存在
            self.s3_client.head_object(
                Bucket=self.bucket_name,
                Key=file_path
            )

            return True

        except ClientError as e:
            if e.response['Error']['Code'] == '404':
                return False
            else:
                logger.error(f"Failed to check file existence: {e}")
                return False
        except Exception as e:
            logger.error(f"Failed to check file existence: {e}")
            return False

    async def list_files(self, prefix: str = "") -> list:
        """
        列出文件

        Args:
            prefix: 文件路径前缀

        Returns:
            文件列表
        """
        try:
            response = self.s3_client.list_objects_v2(
                Bucket=self.bucket_name,
                Prefix=prefix
            )

            files = []
            if 'Contents' in response:
                for obj in response['Contents']:
                    files.append({
                        'key': obj['Key'],
                        'size': obj['Size'],
                        'last_modified': obj['LastModified'],
                        'url': f"{self.endpoint_url}/{self.bucket_name}/{obj['Key']}"
                    })

            return files

        except Exception as e:
            logger.error(f"Failed to list files: {e}")
            return []

    async def get_file_info(self, file_url: str) -> Optional[dict]:
        """
        获取文件信息

        Args:
            file_url: 文件URL

        Returns:
            文件信息字典
        """
        try:
            # 从URL解析文件路径
            if f"/{self.bucket_name}/" in file_url:
                file_path = file_url.split(f"/{self.bucket_name}/", 1)[1]
            else:
                file_path = file_url

            # 获取文件信息
            response = self.s3_client.head_object(
                Bucket=self.bucket_name,
                Key=file_path
            )

            return {
                'key': file_path,
                'size': response['ContentLength'],
                'last_modified': response['LastModified'],
                'content_type': response.get('ContentType', 'application/octet-stream'),
                'url': file_url
            }

        except ClientError as e:
            if e.response['Error']['Code'] == '404':
                return None
            else:
                logger.error(f"Failed to get file info: {e}")
                return None
        except Exception as e:
            logger.error(f"Failed to get file info: {e}")
            return None